#pragma once

#include <vector>

class DeleteNullIdException
{
};

class IdPoolOverflowException
{
};

template < class CONCRETE_POOL >
class IdPool
{
public:
	class Id
	{
		friend class IdPool < CONCRETE_POOL >;
	public:
		Id ()
		: id ( -1 )
		{
		}
		bool operator< ( const Id & operand ) const
		{
			return id < operand.id;
		}
		
	private:
		Id ( int id )
		: id ( id )
		{
		}
		bool IsNull () const
		{
			return id == -1;
		}
	private:
		int id;
	};
	
public:
	IdPool ( int maxId )
	: lastId ( 0 )
	{
		idsInUse.resize ( maxId, false );
	}
	
	Id CreateNewId ()
	{
		if ( std::size_t ( lastId ) >= idsInUse.size () )
			FindEmptyLastId ();
		idsInUse [ lastId ] = true;
		return Id ( lastId++ );
	}

	bool HasId ( const Id & id ) const
	{
		if ( id.IsNull () )
			return false;
		else
		{
			assert ( std::size_t ( id.id ) < idsInUse.size () );
			return idsInUse.at ( id.id );
		}
	}
	
	void DeleteId ( const Id & id )
	{
		if ( id.IsNull () )
			throw DeleteNullIdException ();
		assert ( std::size_t ( id.id ) < idsInUse.size () );
		idsInUse.at ( id.id ) = false; 
	}
	
private:
	void FindEmptyLastId ()
	{
		for ( lastId = 0; lastId < int ( idsInUse.size () ); lastId++ )
			if ( ! idsInUse.at ( lastId ) )
				return;
		throw IdPoolOverflowException ();
	}
	
private:
	int lastId;
	std::vector < bool > idsInUse;
};
